package com.gylang.crypto.resolver;

import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONPath;
import com.gylang.crypto.annotation.CryptoRequest;
import com.gylang.crypto.crypto.CryptoContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 入参解析器 统一处理客户端发送得密文, 对密文进行解密, 实现业务与加解密得解耦
 *
 * @author gylang
 * data 2020/10/27
 * @version v0.0.1
 */
@Slf4j
public class CryptoArgumentResolver implements HandlerMethodArgumentResolver, InitializingBean {

    @Autowired
    private CryptoContext cryptoContext;
    @Autowired(required = false)
    private List<DecryptKeyResolver> decryptKeyResolverList;

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.hasParameterAnnotation(CryptoRequest.class);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {

        log.info("同一解密");
        // 获取含有注解 CryptRequest的入参类型
        Class<?> paramType = methodParameter.getParameterType();
        CryptoRequest cryptoRequest = methodParameter.getParameterAnnotation(CryptoRequest.class);
        if (null != cryptoRequest) {
            // 获取请求参数 请求头 方法注解
            HttpServletRequest httpServletRequest = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
            assert httpServletRequest != null;
            String requestBody = IoUtil.read(httpServletRequest.getInputStream(), StandardCharsets.UTF_8);
            // 尝试从注解中获取 加密密钥 解密密钥
            String decryptKey = cryptoRequest.decryptKey();
            String answerKey = cryptoRequest.answerKey();
            // 从密钥处理器中获取密钥
            for (DecryptKeyResolver decryptKeyResolver : decryptKeyResolverList) {
                if (decryptKeyResolver.support(requestBody, httpServletRequest, cryptoRequest)) {
                    decryptKey = decryptKeyResolver.decryptKey(requestBody, httpServletRequest, cryptoRequest);
                    answerKey = decryptKeyResolver.answerKey(requestBody, httpServletRequest, cryptoRequest);
                    break;
                }
            }
            // 解密
            String decrypt = cryptoContext.decrypt(cryptoRequest.type(), decryptKey, (String) JSONPath.read(requestBody, cryptoRequest.encryptedPath()));
            // 签名
            cryptoContext.answer(cryptoRequest.type(), answerKey, (String) JSONPath.read(requestBody, cryptoRequest.encryptedPath()));
            // 调用业务逻辑
            return JSON.parseObject(decrypt, paramType);
        }
        return null;
    }


    @Override
    public void afterPropertiesSet() {

        if (null == decryptKeyResolverList) {
            decryptKeyResolverList = new ArrayList<>();
        }
    }
}
